<?php
/**
 * TODO отрефакторь это ;)
 * TODO убрать все лишнее
 * TODO написать тесты
 * @since 05.08.2011
 * @author Akulov Denis <akulov.d.g@gmail.com>
 */
class C_Curd extends MVC_Controller_Acp {

    public function _accessDeniedHandler($strMethodName, $arParams) {
        $arExp = array('pool_adding', 'meta_step2', 'meta_step3', 'meta_step4', 'debug');
        if (in_array($strMethodName, $arExp)) {
            $arAnswer = array();
            $arAnswer['is_error'] = 1;
            $arAnswer['error_message'] = '_reload_';
            $arAnswer['is_access_denied'] = 1;
            print JSON_Translator::encode($arAnswer);
            return ;
        }
        parent::_accessDeniedHandler($strMethodName, $arParams);
    }

    public function index () {
        /* @var $objCurd M_Curd */
        $objCurd = $this->_getModel('Curd');
        $objCurd->init('');

        $this->_initLanguage();

        $this->_addView('Curd_Meta_List')
             ->_addVariable('list', $objCurd->getModulesList());
    }


    /**
     * Возможно все модули относящиеся к meta-модели отнести в отдельную
     * Подумать как все это можно вписать в модель транзакции
     * TODO rename transaction_add ?
     */
    public function pool_adding () {
        $objCurd = $this->_getModel('Curd');
        $objCurd->init('');

        $objDataPool = new DataPool($this->_SESSION(), 'ADD_NEW_CURD');

        if (!$objDataPool->isValidUid($this->_GET_Item('uid'))) {
            print JSON_Translator::encode(array(
                'is_error' => 1,
                'error_message' => 'Не верный UID. Работа не может быть продолжена. <a href="/curd/meta_step1/">Попробовать снова</a>'
            ));
            $objDataPool->clean();
            return;
        }

        $arData = array();
        switch ($this->_GET_Item('state')) {
            case 0:
                if (
                    !$this->_GET()->isExists('table_name') ||
                    !in_array($this->_GET_Item('table_name'), $objCurd->getFreeTables())
                ) {
                    print JSON_Translator::encode(
                        array(
                            'is_error'      => 1,
                            'error_message' => 'Выберите таблицу из списка доступных'
                        )
                    );
                    return;
                }
                $arResult['table_name'] = $this->_GET_Item('table_name');
            break;
            case 1:
                $arResult['module_title']       = $this->_GET_Item('module_title');
                $arResult['main_field']  = $this->_GET_Item('main_field');
                $arResult['table_alias']  = $this->_GET_Item('table_alias');
                $arResult['functions']   = $this->_GET_Item('functions');
                if (empty($arResult['table_alias'])) {
                    print JSON_Translator::encode(
                    array(
                        'is_error'      => 1,
                        'error_message' => 'Псевдоним для таблицы не должен быть пустым'
                    )
                    );
                    return;
                }
                if (empty($arResult['module_title'])) {
                    print JSON_Translator::encode(
                        array(
                            'is_error'      => 1,
                            'error_message' => 'Название модуля не должно быть пустым'
                        )
                    );
                    return;
                }
                if (empty($arResult['main_field'])) {
                    print JSON_Translator::encode(
                        array(
                            'is_error'      => 1,
                            'error_message' => 'Не указано главное поле в таблице'
                        )
                    );
                    return;
                }
                $arFields = $objCurd->getFieldsListByTable($this->_GET_Item('table_name'));
                if(!in_array($arResult['main_field'], $arFields)) {
                    print JSON_Translator::encode(
                        array(
                            'is_error'      => 1,
                            'error_message' => 'Выбранное поле не может быть главным в таблице'
                        )
                    );
                    return;
                }
                if (empty($arResult['functions'])) {
                    print JSON_Translator::encode(
                        array(
                            'is_error'      => 1,
                            'error_message' => 'Должно быть доступно хотя бы одно действие'
                        )
                    );
                    return;
                }
                $arAllAccessActionsList = $objCurd->getAllAccessActionsList();
                foreach ($arResult['functions'] as $function) {
                    if (!in_array($function, $arAllAccessActionsList)) {
                        print JSON_Translator::encode(
                            array(
                                'is_error'      => 1,
                                'error_message' => 'Данное действие : ('.$function.') не поддерживается'
                            )
                        );
                        return;
                    }
                }
            break;
            case 2:
                $field = $this->_GET_Item('field_name');
                $arResult[$field]['field_alias'] = $this->_GET_Item('alias');
                $arResult[$field]['edit_method'] = $this->_GET_Item('input_method');
                $arResult[$field]['display_in_catalog'] = $this->_GET_Item('catalog');
                $arResult[$field]['sorting_in_catalog'] = $this->_GET_Item('enable_sorting');

                // получим список поддерживаемых действий
                $arSession = $this->_SESSION_Item('ADD_NEW_CURD');
                if (empty($arSession['DATA'][1]['functions'])) {
                    return ;
                }

                $arAccessActions = $arSession['DATA'][1]['functions'];

                if (empty($arResult[$field]['field_alias'])) {
                    print JSON_Translator::encode(
                        array(
                            'is_error'      => 1,
                            'error_message' => 'Необходимо указать наименование поля'
                        )
                    );
                    return;
                }

                if (in_array('is_access_to_create', $arAccessActions) || in_array('is_access_to_editing', $arAccessActions)) {
                    if (empty($arResult[$field]['edit_method'] )) {
                        print JSON_Translator::encode(
                            array(
                                'is_error'      => 1,
                                'error_message' => 'Необходимо указать метод редактирования'
                            )
                        );
                        return;
                    }
                }
            break;

            default:
                print JSON_Translator::encode(array(
                    'is_error' => 1,
                    'error_message' => 'Оброботчик указанного состояние отсуствует'
                ));
                return;
            break;
        }

        $objDataPool->writing($this->_GET_Item('state'), $arResult);

        print JSON_Translator::encode($objDataPool->getDataByState(0));

    }


    /**
     *
     * TODO rename to addModule (addmodule, add_module)
     */
    public function meta_step1 () {
        $objCurd = $this->_getModel('Curd');
        $objCurd->init('');

        $this->_SESSION()->delete('ADD_NEW_CURD');
        $objDataPool = new DataPool($this->_SESSION(), 'ADD_NEW_CURD');

        $this->_initLanguage();
        $this->_addView('Curd_Meta_Step1')
             ->_addVariable('tables', $objCurd->getFreeTables())
             ->_addVariable('UID', $objDataPool->getUid());
    }


    public function meta_step2 () {
        $objCurd = $this->_getModel('Curd');
        $objCurd->init('');

        // Генерировать uid

        $this->_initLanguage();
        $this->_addView('Curd_Meta_Step2')
             ->_addVariable('fields', $objCurd->getFieldsByTable($this->_GET_Item('table')));
    }


    public function meta_step3 () {
        $objCurd = $this->_getModel('Curd');
        $objCurd->init('');


        // получим список поддерживаемых действий
        $arSession = $this->_SESSION_Item('ADD_NEW_CURD');
        if (empty($arSession['DATA'][1]['functions'])) {
            return ;
        }

        $arAccessActions = $arSession['DATA'][1]['functions'];

        $this->_initLanguage();
        $this->_addView('Curd_Meta_Step3')
             ->_addVariable('fields', $objCurd->getFieldsByTable($this->_GET_Item('table')))
             ->_addVariableFromContainer($this->_GET(), 'table')
             ->_addVariable('access_actions', $arAccessActions);
    }


    public function meta_step4 () {
        $objCurd = $this->_getModel('Curd');
        $objCurd->init('');

        $arSession = $this->_SESSION_Item('ADD_NEW_CURD');

        if (empty($arSession['DATA'][1]['functions'])) {
            print 'Работа не может быть продолжена. <a href="/curd/meta_step1/">Попробовать снова</a>';
            return ;
        }

        $arAccessActions = $arSession['DATA'][1]['functions'];

        $objView = $this->_addView('Curd_Meta_Step4')
             ->_addVariableFromContainer($this->_GET(), 'field')
             ->_addVariableFromContainer($this->_GET(), 'table')
             ->_addVariable('edit_methods', $objCurd->getEditMethods())
             ->_addVariable('access_actions', $arAccessActions);

        $strField = $this->_GET_Item('field');

        if (!empty($strField) && isset($arSession['DATA'][2][$strField])) {
            $objView->_addVariable('data', $arSession['DATA'][2][$strField]);
        }
    }


    public function commit_adding () {
        $objDataPool = new DataPool($this->_SESSION(), 'ADD_NEW_CURD');

        if (!$objDataPool->isValidUid($this->_GET_Item('uid'))) {
            print JSON_Translator::encode(array(
                        'is_error' => 1,
                        'error_message' => 'Не верный UID. Работа не может быть продолжена. <a href="/curd/meta_step1/">Попробовать снова</a>'
            ));
            $objDataPool->clean();
            return;
        }

        $arResult = $objDataPool->getDataByState(0);

        /* @var $objCurd M_Curd */
        $objCurd = $this->_getModel('Curd');
        $objCurd->init('');

        if ($objCurd->commitAdding(
            $arResult['table_name'],
            $objDataPool->getDataByState(1),
            $objDataPool->getDataByState(2)
        )) {
            print JSON_Translator::encode(
                array(
                   'is_error' => 0,
                   'command'    => 'return to home'
                )
            );
            return;
        } else {
            print JSON_Translator::encode(
                array(
                   'is_error' => 1,
                   'command'    => 'Не возможно зафиксировать изменения'
                )
            );
            return;
        }
    }


    public function meta_edit () {

    }


    public function debug () {
        print_r($this->_SESSION()->getAsArray());
    }


    public function session_clean () {
        $this->_SESSION()->clean();
    }


    public function catalog ($sModelName = '') {
        if (empty($sModelName)) {
            $this->_pageNotFound();
        }

        /* @var $objCurd M_Curd */
        $objCurd = $this->_getModel('Curd');
        $objCurd->init($sModelName);

        //print '<pre>'.print_r($objCurd,1).'</pre>';
        //die();

        /*
         * TODO just do refactoring
        if (!$objCurd->isAccess('of_catalog')) {
            $this->_pageNotFound();
        }
        */

        if (!$objCurd->isAccess('of_catalog')) {
            $this->_pageNotFound();
        }

        $iCurrentPageNumber = $this->_GET_Item('page');

        $this->_initLanguage();

        $this->_addView('Curd_Catalog')
             ->_addVariable('catalog', $objCurd->getPage($iCurrentPageNumber, $this->_GET_Item('sorting_by')))
             ->_addVariable('options', $objCurd->getOptions())
             //->_addVariable('is_show_list_of_actions', $objCurd->isShowListOfActions())
             ->_addVariable('is_show_list_of_actions', 'true')
             ->_addVariable('number_of_pages', $objCurd->getNumberOfPages())
             ->_addVariable('current_page_number',$iCurrentPageNumber)
             ->_addVariable('sorting_by', $this->_GET_Item('sorting_by'))
             ->_addVariable('name_of_model', $sModelName)
             ->_addVariableIfNotEmpty('message_data', $this->_getMessage());

        $this->_addTitle($objCurd->getOptionsItem('title'));
    }


    public function view ($strNameOfModel = '') {
        if (empty($strNameOfModel)) {
            $this->_pageNotFound();
        }

        /* @var $objCurd M_Curd */
        $objCurd = $this->_getModel('Curd');
        $objCurd->init($strNameOfModel);

        $this->_initLanguage();

        $this->_addView('Curd_View')
             ->_addVariable('options', $objCurd->getOptions())
             ->_addVariable('element', $objCurd->element($this->_GET_Item('id')));

    }


    public function edit ($strNameOfModel = '') {
        if (empty($strNameOfModel)) {
            $this->_pageNotFound();
        }

        /* @var $objCurd M_Curd */
        $objCurd = $this->_getModel('Curd');
        $objCurd->init($strNameOfModel);

        $this->_initLanguage();

        //print '<pre>'.print_r($objCurd->getFields(),1).'</pre>'; die();
        $this->_addView('Curd_Edit')
             ->_addVariable('options', $objCurd->getOptions())
             ->_addVariable('name_of_model', $strNameOfModel)
             ->_addVariable('element', $objCurd->element($this->_GET_Item('id')))
             ->_addVariable('fields', $objCurd->getFields());
    }


    public function _postEdit ($strNameOfModel = '') {
        if (empty($strNameOfModel)) {
            $this->_pageNotFound();
        }

        /* @var $objCurd M_Curd */
        $objCurd = $this->_getModel('Curd');
        $objCurd->init($strNameOfModel);

        $objCurd->update($this->_GET_Item('id'), $this->_POST()->getAsArray());


        $arMessageData = $objCurd->element($this->_GET_Item('id'));
        $arMessageData['ts'] = time();
        $arMessageData['message'] = 'EDIT_MESSAGE';
        $this->_SESSION()->set('message_data', $arMessageData);

        $this->_redirect('/curd/catalog/'.$strNameOfModel.'?edit_id='.$this->_GET_Item('id'));
    }



    public function add ($strNameOfModel = '') {
        if (empty($strNameOfModel)) {
            $this->_pageNotFound();
        }

        /* @var $objCurd M_Curd */
        $objCurd = $this->_getModel('Curd');
        $objCurd->init($strNameOfModel);

        $this->_initLanguage();

        $this->_addView('Curd_Create')
             ->_addVariable('options', $objCurd->getOptions())
             ->_addVariable('name_of_model', $strNameOfModel)
             ->_addVariable('fields', $objCurd->getFields());
    }


    public function _postAdd ($strNameOfModel = '') {
        if (empty($strNameOfModel)) {
            $this->_pageNotFound();
        }

        /* @var $objCurd M_Curd */
        $objCurd = $this->_getModel('Curd');
        $objCurd->init($strNameOfModel);

        $id = $objCurd->create($this->_POST()->getAsArray());

        $arMessageData = $objCurd->element($id);
        $arMessageData['ts'] = time();
        $arMessageData['message'] = 'ADD_MESSAGE';
        $this->_SESSION()->set('message_data', $arMessageData);

        $this->_redirect('/curd/catalog/'.$strNameOfModel);
    }


    public function delete ($strNameOfModel) {
        if (empty($strNameOfModel)) {
            $this->_pageNotFound();
        }

        $id = $this->_GET_Item('id');
        if (empty($id)) {
            $this->_pageNotFound();
        }

        if (!$this->_isRefererValid($strNameOfModel)) {
            $this->_pageNotFound();
        }

        /* @var $objCurd M_Curd */
        $objCurd = $this->_getModel('Curd');
        $objCurd->init($strNameOfModel);

        $arDeletedData = $objCurd->element($id);

        $objCurd->delete($id);

        if (!$objCurd->isExists($id)) {
            $arDeletedData['ts'] = time();
            $arDeletedData['message'] = 'DELETE_MESSAGE';
            $this->_SESSION()->set('message_data', $arDeletedData);
        }

        $this->_redirect('curd/catalog/'.$strNameOfModel);
    }


    private function _getMessage () {
        $arMessageData = $this->_SESSION_Item('message_data');
        $this->_SESSION()->delete('message_data');

        // Просрочено время
        if (!empty($arMessageData) && (time() - $arMessageData['ts'] > 60)) {
            unset($arMessageData);
        }

        return $arMessageData;
    }


    private function _initLanguage ($lang = 'Ru') {
        $this->_addView('Curd_Languages_'.$lang);
    }

}